/*
 * acooly.cn Inc.
 * Copyright (c) 2016 All Rights Reserved.
 * create by zhangpu 
 * date:2016年4月4日
 *
 */
package com.acooly.module.openapi.client.provider.yinsheng.marshall;

import com.acooly.core.utils.Reflections;
import com.acooly.core.utils.Strings;
import com.acooly.core.utils.validate.Validators;
import com.acooly.module.openapi.client.api.anotation.ApiItem;
import com.acooly.module.openapi.client.api.exception.ApiClientException;
import com.acooly.module.openapi.client.provider.yinsheng.OpenAPIClientYinShengProperties;
import com.acooly.module.openapi.client.provider.yinsheng.YinShengConstants;
import com.acooly.module.openapi.client.provider.yinsheng.domain.YinShengApiMessage;
import com.acooly.module.openapi.client.provider.yinsheng.domain.YinShengRequest;
import com.acooly.module.openapi.client.provider.yinsheng.utils.JsonMarshallor;
import com.acooly.module.openapi.client.provider.yinsheng.utils.SignUtils;
import com.acooly.module.safety.Safes;
import com.acooly.module.safety.key.KeyLoadManager;
import com.acooly.module.safety.signature.SignTypeEnum;
import com.acooly.module.safety.signature.SignerFactory;
import com.acooly.module.safety.support.KeyStoreInfo;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;

/**
 * @author zhangpu
 */
@Slf4j
public class YinShengMarshallSupport {

    @Autowired
    protected OpenAPIClientYinShengProperties openAPIClientYinShengProperties;

    @Autowired
    protected SignerFactory signerFactory;

    @Autowired
    private KeyLoadManager keyStoreLoadManager;

    private static JsonMarshallor jsonMarshallor = JsonMarshallor.INSTANCE;

    protected OpenAPIClientYinShengProperties getProperties() {
        return openAPIClientYinShengProperties;
    }

    public SignerFactory getSignerFactory() {
        return signerFactory;
    }

    protected Map<String, String> doMarshall(YinShengRequest source) {
        doVerifyParam(source);
        Map<String, String> requestDataMap = getRequestDataMap(source);
        String signContent = SignUtils.getSignContent(requestDataMap);
        log.debug("待签字符串:{}", signContent);
        source.setSign(SignUtils.urlEncode(doSign(signContent, source)));
        requestDataMap.put(YinShengConstants.SIGN, source.getSign());
        String bizContentData = requestDataMap.get(YinShengConstants.BIZ_CONTENT);
        if(Strings.isNotBlank(bizContentData)) {
            String stantJsonStr = SignUtils.encodeBizContent(bizContentData);
            requestDataMap.put(YinShengConstants.BIZ_CONTENT,stantJsonStr);
        }
        return requestDataMap;
    }

    /**
     * 获取代签map
     *
     * @param source
     * @return
     */
    protected Map<String, String> getRequestDataMap(YinShengRequest source) {
        Map<String, String> requestData = Maps.newTreeMap();
        Set<Field> fields = Reflections.getFields(source.getClass());
        String key = null;
        Object value = null;
        for (Field field : fields) {
            value = Reflections.getFieldValue(source, field.getName());
            if (value == null) {
                continue;
            }
            ApiItem apiItem = field.getAnnotation(ApiItem.class);
            if (apiItem == null) {
                key = field.getName();
            } else {
                if (!apiItem.sign()) {
                    continue;
                }
                key = apiItem.value();
                if (Strings.isBlank(key)) {
                    key = field.getName();
                }
            }
            if (field.getType() != String.class) {
                value = jsonMarshallor.marshall(value);
            }
            if(Strings.isNotBlank((String) value)) {
                requestData.put(key, (String) value);
            }
        }
        return requestData;
    }

    /**
     * 将对象转化为String
     *
     * @param object
     * @return
     */

    private String convertString(Object object) {
        if (object == null) {
            return null;
        }
        return object.toString();
    }

    /**
     * 校验参数
     *
     * @param source
     */
    protected void doVerifyParam(YinShengApiMessage source) {
        try {
            source.doCheck();
            Validators.assertJSR303(source);
        } catch (Exception e) {
            throw new ApiClientException(e.getMessage());
        }
    }

    /**
     * 签名 优先获取传进来的，如果传进来没有则用配置文件中的
     *
     * @param waitForSign
     * @param source
     * @return
     */
    protected String doSign(String waitForSign, YinShengRequest source) {
        KeyStoreInfo keyStoreInfo = getKeyStoreInfo(source);
        String signStr = Safes.getSigner(SignTypeEnum.Cert).sign(waitForSign, keyStoreInfo);
        return signStr;
    }

    protected String doSign(String waitForSign, String partnerId) {
        KeyStoreInfo keyStoreInfo = getKeyStoreInfo(partnerId);
        String signStr = Safes.getSigner(SignTypeEnum.Cert).sign(waitForSign, keyStoreInfo);
        return signStr;
    }

    /**
     * 验签
     *
     * @param signature
     * @param plain
     * @return
     */
    protected void doVerifySign(String signature, String plain, String partnerId) {
        Safes.getSigner(SignTypeEnum.Cert).verify(plain, getKeyStoreInfo(partnerId), signature);
    }

    /**
     * 获取keyStoreInfo
     *
     * @return
     */
    protected KeyStoreInfo getKeyStoreInfo(YinShengRequest source) {
        KeyStoreInfo keyStoreInfo = keyStoreLoadManager.load(source.getPartner_id(), YinShengConstants.PROVIDER_NAME);
        return keyStoreInfo;
    }

    /**
     * 获取keyStoreInfo
     *
     * @return
     */
    protected KeyStoreInfo getKeyStoreInfo(String partnerId) {
        KeyStoreInfo keyStoreInfo = keyStoreLoadManager.load(partnerId, YinShengConstants.PROVIDER_NAME);
        return keyStoreInfo;
    }

    protected void beforeMarshall(YinShengApiMessage message) {
        if(Strings.isBlank(message.getPartner_id())) {
            message.setPartner_id(getProperties().getPartnerId());
        }
    }

}
